#pragma once

#include "hdmap/HDMapExports.hpp"
#include "hdmap/HDMapCommon.hpp"

namespace Navinfo
{
	namespace Engine
	{
		/**
		 *  @brief attribute of road
		 */
		class HDMAP_API_PUBLIC HDMapRoadAttribute
		{
		public:
			/**
			 *  @brief Construction function
			 */
			HDMapRoadAttribute(DataSource::NDSFixRoadAttribute& ndsFixRoadAttribute, uint16_t nStartPos, uint16_t nEndPos);
			HDMapRoadAttribute() = default;
			/**
			 *  @brief destruction function
			 */
			virtual ~HDMapRoadAttribute() = default;
		public:
			/**
			 *  @brief get the attribute begin index on road geometry
			 */
			const uint16_t GetStartPosition() const { return m_nStartPos; }
			/**
			 *  @brief get the attribute end index on road geometry
			 */
			const uint16_t GetEndPosition() const { return m_nEndPos; }
			/**
			 *  @brief get toll status of road
			 */
			const HDMapDirection GetToll() const { return m_eToll; }
			/**
			 *  @brief query whether road is ferry
			 */
			const bool GetFerry() const { return m_bFerry; }
			/**
			 *  @brief query whether road is tunnel
			 */
			const bool GetTunnel() const { return m_bTunnel; }
			/**
			 *  @brief query whether road is bridge
			 */
			const bool GetBridge() const { return m_bBridge; }
			/**
			 *  @brief query whether road is a controlled access road, for example a motorway or freeway.
			 */
			const bool GetControlledAccess() const { return m_bControlledAccess; }
			/**
			 *  @brief query whether road is a road that leads to or from a service area or is part of a service area.
			 */
			const bool GetServiceArea() const { return m_bServiceArea; }
			/**
			 *  @brief query whether road in Urban
			 */
			const bool GetUrban() const { return m_bUrban; }
			/**
			 *  @brief query whether road is a part of complex intersection
			 */
			const bool GetComplexIntersection() const { return m_bComplexIntersection; }
			/**
			 *  @brief query whether road is a part if junction
			 */
			const bool GetPluralJunction() const { return m_bPluralJunction; }
			/**
			 *  @brief query whether road is a motorway
			 */
			const bool GetMotorway() const { return m_bMotorway; }

		private:
			uint16_t					m_nStartPos;			///< attribute begin from the start point of road geometry
			uint16_t					m_nEndPos;				///< attribute stop at the end point of road geometry
			HDMapDirection				m_eToll;				///< Indicates if the link or road geometry line represents a toll road or	has a toll booth
			bool						m_bFerry;				///< Indicates whether the link or road geometry is ferry
			bool						m_bTunnel;				///< Indicates whether the link or road geometry is tunel
			bool						m_bBridge;				///< Indicates whether the link or road geometry is bridge
			bool						m_bControlledAccess;	///< Indicates if the link or road geometry line represents a controlled access road, for example a motorway or freeway.
			bool						m_bServiceArea;			///< Indicates if the link or road geometry line represents a road that leads to or from a service area or is part of a service area.
			bool						m_bUrban;				///< 
			bool						m_bComplexIntersection;	///< 
			bool						m_bPluralJunction;		///< 
			bool						m_bMotorway;			///< 
		};
		
		class HDMAP_API_PUBLIC HDMapRoadInfo
		{
		public:
			HDMapRoadInfo() = default;
			HDMapRoadInfo(DataSource::NDSLink &ndsLink);
			virtual ~HDMapRoadInfo() = default;

			/**
			 *  @brief get road ID
			 *  @return road ID
			 */
			const uint64_t GetID() const { return m_nID; }
			/**
			 *  @brief Get the tile ID where the road is located
			 *  @return tile ID
			 */
			const uint32_t GetTileID() const { return m_nTileID; }
			/**
			 *  @brief Get the length of the road
			 *  @return length of the road.  unit: cm
			 */
			const uint32_t GetLength() const { return m_nLength; }
			/**
			 *  @brief Get the name of the road
			 *  @return name of the road
			 */
			const std::string GetName() const{ return m_strName; }
			/**
			 *  @brief Get a shape point coordinate list of the road
			 *  @return shape point
			 */
			const std::vector<Navinfo::Engine::Math::Vec3d>& GetGeometryPoints() const { return m_vtGeometryPoints; }
			/**
			 *  @brief Get a list of all source road information
			 *  @return list of all source road information
			 */
			const std::vector<std::weak_ptr<HDMapRoadInfo>>& GetSourceRoads() const { return m_vtSourceRoads; }
			/**
			 *  @brief Get a list of all destination road information
			 *  @return  list of all destination road information
			 */
			const std::vector<std::weak_ptr<HDMapRoadInfo>>& GetDestinationRoads() const { return m_vtDestinationRoads; }
			/**
			 *  @brief Get a list of all attribute information on this road
			 *  @return all attribute information on this road
			 */
			const std::vector<std::shared_ptr<HDMapRoadAttribute>>& GetRoadAttributes() const { return m_vtRoadAtrributes; }
			/**
			 *  @brief Get a list of all lanes on this road along the direction
			 *  @return list of all lanes
			 */
			const std::vector<std::vector<std::weak_ptr<HDMapLaneInfo>>>& GetLanes(bool bPositive = true) const { return bPositive ? m_vtPositiveLanes : m_vtNegtiveLanes; }
			/**
			 *  @brief Get a list of all lanegroups on this road along the direction.
			 *  @return list of all lanegroups
			 */
			const std::vector<std::weak_ptr<HDMapLaneGroupInfo>>& GetLaneGroups(bool bPositive = true) const { return bPositive ? m_vtPositiveLaneGroups : m_vtNegtiveLaneGroups; }
			/**
			 *  @brief get speed limit value
			 */
			const std::vector<std::shared_ptr<HDMapSpeedLimit>>& GetRoadSpeedLimit() const { return m_vtRoadSpeedLimit; }

			/**
			 *  @brief Extend attribute include curvature and slop value
			 */
			const std::vector<HDMapExtendAttribute> &GetExtendAttribute() const { return m_ExtendAttrList; }

			/**
			 *  @brief Get right lane boundandaries of this road
			 *  @return list of right laneboundary
			 */
			const std::vector<std::weak_ptr<HDMapLaneBoundariesInfo>>& GetRightLaneBoundaries() const { return m_vtRightLaneBoundaries; }

			/**
			 *  @brief Get left lane boundandaries of this road
			 *  @return list of left laneboundary
			 */
			const std::vector<std::weak_ptr<HDMapLaneBoundariesInfo>>& GetLeftLaneBoundaries() const { return m_vtLeftLaneBoundaries; }

			/**
			 *  @brief get road function class
			 */
			const uint8_t GetFunctionalRoadClass() const { return m_nFunctionalRoadClass; }

			/**
			 *  @brief get type of link
			 */
			const HDMapLinkType GetLinkType() const { return m_eLinkType; }

			/**
			 *  @brief get travel direction of road
			 */
			const HDMapDirection GetTravelDirection() const { return m_eTravelDirection; }

			/**
			 *  @brief Query vehicle is restricted or not
			 */
			bool IsRestrict(HDMapVehicleTypes vtype, HDMapDirection driveDir) const
			{
				if (driveDir == HDMapDirection::IN_POSITIVE_DIRECTION) {
					return QueryRestrict(mAccessCondition, vtype);
				}
				else if (driveDir == HDMapDirection::IN_NEGATIVE_DIRECTION) {
					return QueryRestrict(mNagAccessCondition, vtype);
				}
				else {
					return false;
				}
			}

			/**
			 *  @brief Get All Median Attribute of road
			 */
			
			const std::vector<HDMapRoadMedian> &GetMedianAttribute() const { return m_vtMedian; }

			/**
			*  @brief get the divider attribute of the road
			*  @return the divider attribute of this road
			*/
			const std::vector<HDMapDivider> &GetDividers() const { return m_vtDividers; }

		public:
			/**
			 *  @brief Prohibition condition of time period and vechile type
			 */
			struct HDMapRoadProhibitedCondition{
				uint8_t					mIsValid;		///< ProhibitedCondition is valid  1:means valid 0:means invalid
				VehicleTypeSequence		vehicleType;	///< allowed vehicle type (each bit indicate one type of vehicale)
				std::vector<TimePeriod> timePeriod;		///< valid Time range
			};
		private:
			bool QueryRestrict(const HDMapRoadProhibitedCondition &condition, HDMapVehicleTypes vtype) const {
				if (0 == condition.mIsValid)
					return false;
				if (condition.vehicleType & (1 << vtype))
					return true;
				return false;
			}

		private:
			friend class HDMapImpl;
			uint64_t												m_nID;						///< road id
			uint32_t												m_nTileID;					///< the tile ID where the road is located
			uint32_t												m_nLength;					///< length of the road unit cm
			std::string												m_strName;					///< name of the road
			uint8_t													m_nFunctionalRoadClass;		///< A road with a lower class is likely to be used for local routes only. 0 is the highest class, 7 the lowest one
			HDMapLinkType											m_eLinkType;				///< Properties of a link or road geometry line that are used for guidance purposes
			HDMapDirection											m_eTravelDirection;			///< Indicates whether the road represented by the link or road geometry line is traversable and in which direction
			std::vector<Navinfo::Engine::Math::Vec3d>				m_vtGeometryPoints;			///< all shape point coordinates of the road
			std::vector<Navinfo::Engine::Math::LineSegment2d>		m_vtSegments;				///< all segments of the road
			std::vector<std::shared_ptr<HDMapRoadAttribute>>		m_vtRoadAtrributes;			///< all attribute of the road
			std::vector<std::shared_ptr<HDMapSpeedLimit>>			m_vtRoadSpeedLimit;			///< all speed limit of the road
			std::vector<std::weak_ptr<HDMapRoadInfo>>				m_vtSourceRoads;			///< all source road information
			std::vector<std::weak_ptr<HDMapRoadInfo>>				m_vtDestinationRoads;		///< all destination road information
			std::vector<std::vector<std::weak_ptr<HDMapLaneInfo>>>	m_vtPositiveLanes;			///< all positive lane on the road
			std::vector<std::vector<std::weak_ptr<HDMapLaneInfo>>>	m_vtNegtiveLanes;			///< all negtive lane on the road
			std::vector<std::weak_ptr<HDMapLaneGroupInfo>>			m_vtPositiveLaneGroups;		///< all positive lane group of the road>
			std::vector<std::weak_ptr<HDMapLaneGroupInfo>>			m_vtNegtiveLaneGroups;		///< all negtive lane group of the road>
			std::vector<HDMapExtendAttribute>						m_ExtendAttrList;			///< 
			std::vector<std::weak_ptr<HDMapLaneBoundariesInfo>>		m_vtRightLaneBoundaries;	///< 
			std::vector<std::weak_ptr<HDMapLaneBoundariesInfo>>		m_vtLeftLaneBoundaries;		///< 
			HDMapRoadProhibitedCondition							mAccessCondition;			///< 
			HDMapRoadProhibitedCondition							mNagAccessCondition;		///< 
			std::vector<std::weak_ptr<HDMapRoadInfo>>				mMultiDigitizedRoads;		///< 
			std::vector<HDMapDivider>								m_vtDividers;
			bool													m_IsMultiDigitized;			///<

			std::vector<HDMapRoadMedian>							m_vtMedian;
		};
	}
}
namespace Navinfo{
	namespace HDMap{
		typedef Navinfo::Engine::HDMapRoadInfo Road;
	}
}